/**
 * @file hash_benchmark.cpp
 * @brief 哈希表性能基准测试程序
 * 
 * @details 该程序用于测试和比较不同类型哈希表实现的性能，
 * 包括数组实现的哈希表（MEOrderBook）和基于unordered_map的哈希表
 * （UnorderedMapMEOrderBook）。通过测量添加和取消订单操作的CPU时钟周期数
 * 来评估性能。
 */

#include "matcher/matching_engine.h"
#include "matcher/unordered_map_me_order_book.h"

/**
 * @brief 测试循环次数
 * 
 * @details 定义每个测试运行的操作数量，设置为100,000次以确保测试结果的统计显著性。
 */
static constexpr size_t loop_count = 100000;

/**
 * @brief 测量哈希表性能的函数
 * 
 * @tparam T 订单簿类型，可以是MEOrderBook或UnorderedMapMEOrderBook
 * @param order_book 订单簿对象指针
 * @param client_requests 客户端请求向量，包含要执行的新建和取消订单操作
 * @return size_t 每个操作的平均CPU时钟周期数
 * 
 * @details 该函数对指定类型的订单簿进行性能测试，通过执行一系列的新建和取消订单操作，
 * 并测量每个操作所需的CPU时钟周期数。使用rdtsc（Read Time-Stamp Counter）指令获取
 * 高精度的CPU时钟计数。最终返回所有操作的平均时钟周期数。
 */
template<typename T>
size_t benchmarkHashMap(T *order_book, const std::vector<Exchange::MEClientRequest>& client_requests) {
  /**
   * @brief 累计的CPU时钟周期数
   * 
   * @details 用于累计所有操作的CPU时钟周期数，最终将除以操作数量得到平均值。
   */
  size_t total_rdtsc = 0;

  /**
   * @brief 执行测试循环
   * 
   * @details 循环执行指定次数的订单操作，并测量每个操作的执行时间。
   */
  for (size_t i = 0; i < loop_count; ++i) {
    const auto& client_request = client_requests[i];
    switch (client_request.type_) {
      case Exchange::ClientRequestType::NEW: {
        /**
         * @brief 测量新建订单操作
         * 
         * @details 记录开始时间，执行添加订单操作，然后计算所用的时钟周期数。
         */
        const auto start = Common::rdtsc();
        order_book->add(client_request.client_id_, client_request.order_id_, client_request.ticker_id_,
                        client_request.side_, client_request.price_, client_request.qty_);
        total_rdtsc += (Common::rdtsc() - start);
      }
        break;

      case Exchange::ClientRequestType::CANCEL: {
        /**
         * @brief 测量取消订单操作
         * 
         * @details 记录开始时间，执行取消订单操作，然后计算所用的时钟周期数。
         */
        const auto start = Common::rdtsc();
        order_book->cancel(client_request.client_id_, client_request.order_id_, client_request.ticker_id_);
        total_rdtsc += (Common::rdtsc() - start);
      }
        break;

      default:
        break;
    }
  }

  /**
   * @brief 计算并返回平均时钟周期数
   * 
   * @details 将总时钟周期数除以操作数量的两倍（因为每个循环有两个操作：新建和取消）。
   */
  return (total_rdtsc / (loop_count * 2));
}

/**
 * @brief 程序的主函数
 * 
 * @param int 未使用的命令行参数数量
 * @param char** 未使用的命令行参数数组
 * @return int 程序退出状态码
 * 
 * @details 主函数初始化测试环境，生成随机订单请求，然后对两种不同的哈希表实现
 * （数组实现和unordered_map实现）进行性能测试，并输出每种实现的平均操作时钟周期数。
 */
int main(int, char **) {
  /**
   * @brief 初始化随机数生成器
   * 
   * @details 使用固定的种子值0初始化随机数生成器，确保每次运行程序时生成相同的随机序列，
   * 便于比较不同实现的性能。
   */
  srand(0);

  /**
   * @brief 初始化测试环境
   * 
   * @details 创建日志记录器、客户端请求队列、客户端响应队列、市场更新队列和匹配引擎。
   * 这些组件是订单簿运行所需的基础设施。
   */
  Common::Logger logger("hash_benchmark.log");
  Exchange::ClientRequestLFQueue client_requests(ME_MAX_CLIENT_UPDATES);
  Exchange::ClientResponseLFQueue client_responses(ME_MAX_CLIENT_UPDATES);
  Exchange::MEMarketUpdateLFQueue market_updates(ME_MAX_MARKET_UPDATES);
  auto matching_engine = new Exchange::MatchingEngine(&client_requests, &client_responses, &market_updates);

  /**
   * @brief 生成随机订单请求
   * 
   * @details 生成足够数量的随机订单请求，包括新建订单和取消订单。
   * 每个新建订单都有随机的价格、数量和侧向（买入或卖出）。
   * 每个取消订单都是从已生成的订单中随机选择的。
   */
  Common::OrderId order_id = 1000; // 初始订单ID
  std::vector<Exchange::MEClientRequest> client_requests_vec; // 存储生成的订单请求
  Price base_price = (rand() % 100) + 100; // 基准价格，范围为100-199
  
  // 生成足够数量的订单请求
  while (client_requests_vec.size() < loop_count) {
    // 生成随机新建订单
    const Price price = base_price + (rand() % 10) + 1; // 随机价格，基准价格加上1-10的偏移
    const Qty qty = 1 + (rand() % 100) + 1; // 随机数量，范围为2-101
    const Side side = (rand() % 2 ? Common::Side::BUY : Common::Side::SELL); // 随机侧向，买入或卖出

    Exchange::MEClientRequest new_request{Exchange::ClientRequestType::NEW, 0, 0, order_id++, side, price, qty};
    client_requests_vec.push_back(new_request);

    // 生成随机取消订单，从已生成的订单中随机选择一个进行取消
    const auto cxl_index = rand() % client_requests_vec.size();
    auto cxl_request = client_requests_vec[cxl_index];
    cxl_request.type_ = Exchange::ClientRequestType::CANCEL;

    client_requests_vec.push_back(cxl_request);
  }

  /**
   * @brief 测试数组实现的哈希表（MEOrderBook）
   * 
   * @details 创建数组实现的订单簿，运行基准测试，并输出每个操作的平均时钟周期数。
   * 使用若干作用域确保订单簿对象在测试完成后被自动释放。
   */
  {
    auto me_order_book = new Exchange::MEOrderBook(0, &logger, matching_engine);
    const auto cycles = benchmarkHashMap(me_order_book, client_requests_vec);
    std::cout << "ARRAY HASHMAP " << cycles << " CLOCK CYCLES PER OPERATION." << std::endl;
  }

  /**
   * @brief 测试基于unordered_map实现的哈希表（UnorderedMapMEOrderBook）
   * 
   * @details 创建基于unordered_map实现的订单簿，运行基准测试，并输出每个操作的平均时钟周期数。
   * 使用若干作用域确保订单簿对象在测试完成后被自动释放。
   */
  {
    auto me_order_book = new Exchange::UnorderedMapMEOrderBook(0, &logger, matching_engine);
    const auto cycles = benchmarkHashMap(me_order_book, client_requests_vec);
    std::cout << "UNORDERED-MAP HASHMAP " << cycles << " CLOCK CYCLES PER OPERATION." << std::endl;
  }

  /**
   * @brief 程序成功退出
   * 
   * @details 使用EXIT_SUCCESS状态码表示程序成功执行并正常退出。
   */
  exit(EXIT_SUCCESS);
}
